/**
 *    Copyright 2009 Seth Albnaese
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.aquiferserver.client.flex 
{
	import flash.events.EventDispatcher;
	import flash.net.Socket;
	import flash.events.ProgressEvent;
	import flash.utils.ByteArray;
	import org.aquiferserver.client.flex.logging.Log;
	import org.aquiferserver.client.flex.logging.LogFactory;
	
	/**
	 * Core Aquifer client class provides the primary API for game developers
	 * @author Seth Albanese
	 * @version $Id: AquiferClient.as 42 2009-05-13 15:45:10Z salbanese0080@gmail.com $
	 */
	
	
	public class AquiferClient extends EventDispatcher
	{
		protected static var logger:Log = LogFactory.getLog( "org.aquiferserver.client.flex.AquiferClient" );
		
		private var conn:Socket;
		
		private var peers:Array = new Array( );
		private var id:int = 0;
		
		[Bindable( "clientStateChange" )]
		public function get connectedPeers() : Array { return peers.concat(); }		
		
		[Bindable( "clientStateChange" )]
		public function get clientId() : int { return id; }		
		
		[Bindable( "clientStateChange" )]
		public function get connected() : Boolean { return ( conn != null ) ? conn.connected : false; }
		
		public function connect( server:String, port:Number ) : void
		{
			logger.info( "Connecting to " + server + " on port " + port + "..." );
			conn = new Socket();
			conn.addEventListener( ProgressEvent.SOCKET_DATA, socketDataHandler );			
			conn.connect( server, port );
		}
		
		public function close() : void 
		{
			conn.close();
			
			id = 0;
			peers = new Array();			
			
			dispatchEvent( new AquiferClientEvent( AquiferClientEvent.ON_DISCONNECT, { connected:conn.connected } ) );
			dispatchEvent( new AquiferClientEvent( AquiferClientEvent.ON_STATE_CHANGE ) );
		}
		
		public function sendObject( value:Object ) : void 
		{			
			var msg:String = SerializationCodec.serialize( value );
			
			logger.debug( "Sending serialized value : " + msg );
			
			conn.writeUTFBytes ( msg );			
			conn.writeByte( 0x7C );
			conn.flush();
		}
		
		private function socketDataHandler( event:ProgressEvent ) : void
		{
			logger.debug( "Recieved raw data" );
			var resp:String = conn.readUTFBytes( conn.bytesAvailable );			
			
			var message:AquiferMessage = new AquiferMessage( resp.replace( /^\s+|\s+$/g, '' ) );
			
			switch ( message.type )
			{
				case AquiferMessage.MT_PEER:
					dispatchEvent( new AquiferClientEvent( AquiferClientEvent.ON_DATA_RECIEVED, { message:message } ) );
				break;
				
				case AquiferMessage.MT_HANDSHAKE:
					id = message.data.clientId;
					
					logger.info( "SETTING CLIENT ID TO " + id );
					
					if ( message.data.peers != undefined && message.data.peers.length > 0 )
					{
						peers = message.data.peers;
					}
					
					logger.debug( "Confirming handshake" );
					conn.writeUTFBytes( "!_HSCONFIRM|" );
					conn.flush();
					//dispatchEvent( new AquiferClientEvent( AquiferClientEvent.ON_CONNECT, { connected:conn.connected } ) );
					//dispatchEvent( new AquiferClientEvent( AquiferClientEvent.ON_STATE_CHANGE ) );
					
				break;
				
				case AquiferMessage.MT_SERV:
					
					if ( message.data.peer != undefined )
					{						
						var currentPeer:Boolean = false;
						
						for ( var i:int = 0; i < peers.length; i++ )
						{
							logger.debug( peers[ i ] + " = " + message.data.peer );
							if ( peers[ i ] == message.data.peer )
							{
								currentPeer = true;
								logger.debug( "Found existing peer, removing" );
								break;
							}
						}
						
						if ( !currentPeer )
						{
							peers.push( message.data.peer );
							logger.info( "New connected peer with id " + message.data.peer );
							dispatchEvent( new AquiferClientEvent( AquiferClientEvent.ON_PEER_CONNECT, { peer:message.data.peer } ) );
						}
						else
						{
							peers.splice( peers.indexOf( message.data.peer) , 1 );
							logger.info( "Peer disconnected with id " + message.data.peer );
							dispatchEvent( new AquiferClientEvent( AquiferClientEvent.ON_PEER_DISCONNECT, { peer:message.data.peer } ) );
						}
					}
					else
					{
						for each ( var val:* in message.data )
						{
							logger.debug( "Random server message: " + val + " : " + val.toString() ); 
						}
					}
					
					dispatchEvent( new AquiferClientEvent( AquiferClientEvent.ON_STATE_CHANGE ) );
					
				break;
				
				case org.aquiferserver.client.flex.AquiferMessage.MT_CONNECTED:
					logger.debug( "CONNECTION COMPLETE" );
					dispatchEvent( new AquiferClientEvent( AquiferClientEvent.ON_CONNECT, { connected:conn.connected } ) );
					dispatchEvent( new AquiferClientEvent( AquiferClientEvent.ON_STATE_CHANGE ) );
				break;
			}			
		}
	}
	
}